﻿using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

namespace Core
{
    public static partial class Utils
    {
        public class Touch
        {
            private const int DEFAULT_GUI_LAYERS = 1 << 5 | 1 << 6;

            // Used to find if the GUI is in use
            private static List<RaycastResult> tempRaycastResults = new(10);

            // Used by RaycastGui
            private static PointerEventData tempPointerEventData;

            // Used by RaycastGui
            private static UnityEngine.EventSystems.EventSystem tempEventSystem;

            //return Instances.Count > 0 ? Instances[0].guiLayers : (LayerMask)DEFAULT_GUI_LAYERS;
            public static LayerMask CurrentGuiLayers => DEFAULT_GUI_LAYERS;

            public static UnityEngine.EventSystems.EventSystem GetEventSystem()
            {
                var currentEventSystem = UnityEngine.EventSystems.EventSystem.current;

                if (currentEventSystem == null)
                {
                    currentEventSystem = GameObject.FindObjectOfType<UnityEngine.EventSystems.EventSystem>();
                }

                return currentEventSystem;
            }

            /// <summary>This will return true if the specified screen point is over any GUI elements.</summary>
            public static bool PointOverGui(Vector2 screenPosition)
            {
                return RaycastGui(screenPosition).Count > 0;
            }

            /// <summary>This will return all the RaycastResults under the specified screen point using the current layerMask.
            /// NOTE: The first result (0) will be the top UI element that was first hit.</summary>
            public static List<RaycastResult> RaycastGui(Vector2 screenPosition)
            {
                return RaycastGui(screenPosition, CurrentGuiLayers);
            }

            /// <summary>This will return all the RaycastResults under the specified screen point using the specified layerMask.
            /// NOTE: The first result (0) will be the top UI element that was first hit.</summary>
            public static List<RaycastResult> RaycastGui(Vector2 screenPosition, LayerMask layerMask)
            {
                tempRaycastResults.Clear();

                var currentEventSystem = GetEventSystem();

                if (currentEventSystem != null)
                {
                    // Create point event data for this event system?
                    if (currentEventSystem != tempEventSystem)
                    {
                        tempEventSystem = currentEventSystem;

                        if (tempPointerEventData == null)
                        {
                            tempPointerEventData = new PointerEventData(tempEventSystem);
                        }
                        else
                        {
                            tempPointerEventData.Reset();
                        }
                    }

                    // Raycast event system at the specified point
                    tempPointerEventData.position = screenPosition;

                    currentEventSystem.RaycastAll(tempPointerEventData, tempRaycastResults);

                    // Loop through all results and remove any that don't match the layer mask
                    if (tempRaycastResults.Count > 0)
                    {
                        for (var i = tempRaycastResults.Count - 1; i >= 0; i--)
                        {
                            var raycastResult = tempRaycastResults[i];
                            var raycastLayer = 1 << raycastResult.gameObject.layer;

                            if ((raycastLayer & layerMask) == 0)
                            {
                                tempRaycastResults.RemoveAt(i);
                            }
                        }
                    }
                }
                else
                {
                    Debug.LogError(
                        "Failed to RaycastGui because your scene doesn't have an event system! To add one, go to: GameObject/UI/EventSystem");
                }

                return tempRaycastResults;
            }
        }
    }
}
